﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NHibernate;
using Thaire.Investment.BL.DTO;
using Thaire.Investment.BL.Filter;
using Thaire.Investment.BL.ScreenData;
using Thaire.Investment.Domains.Transaction;
using Thaire.Investment.Repository;

namespace Thaire.Investment.BL
{
    public class EquityBL
    {
        ISession _session;
        public EquityBL(ISession session)
        {
            _session = session;
        }

        public List<EquityHeader> SearchEquity(SearchEquityFilter searchData)
        {
            IQueryOver<EquityHeader, EquityHeader> query = _session.QueryOver<EquityHeader>()
               .Where(x => x.EquityHeaderID == x.EquityHeaderID);

            if (searchData.Company.HasValue)
                query.And(x => x.EquityCompanyID == searchData.Company.Value);
            if (searchData.Type.HasValue)
                query.And(x => x.EquityTypeID == searchData.Type.Value);
            if (searchData.Broker.HasValue)
                query.And(x => x.BrokerID == searchData.Broker.Value);
            if (!String.IsNullOrEmpty(searchData.FullName))
                query.And(x => x.FullNameEN == searchData.FullName);
            if (!String.IsNullOrEmpty(searchData.Symbol))
                query.And(x => x.Symbol == searchData.Symbol);
            query.OrderBy(x => x.CreateDate);
            return new List<EquityHeader>(query.List());
        }

        public EquityHeaderScreenData GetEquityHeaderScreenData(int? headerId)
        {
            var data = new EquityHeaderScreenData();
            if (headerId != null)
            {
                data.HeaderDTO = new EquityHeaderDTO();
                var header = new EquityHeaderRepo(SessionManager.CurrentSession).GetByID(headerId.Value);
                data.HeaderDTO.Header = header;
                data.HeaderDTO.Transactions = new EquityTransactionRepo(SessionManager.CurrentSession).GetListByHeaderID(headerId.Value);
                data.HeaderDTO.Prices = new EquityPriceRepo(SessionManager.CurrentSession).GetListByHeaderID(headerId.Value);
                data.HeaderDTO.InvolvedPartyType = new InvolvedPartyTypeRepo(_session).GetByName(header.InvolvedPartyTypeName);
            }
            data.Companies = new CompanyRepo(_session).GetAll().ToList();
            data.Brokers = new BrokerRepo(_session).GetAll().ToList();
            data.InvolvedPartyTypes = new InvolvedPartyTypeRepo(_session).GetAll().ToList();
            data.EquityType = new ReferenceCodeRepo(_session).GetByDomain(ReferenceCodeRepo.EQUITY_TYPE, true);
            data.RelateType = new ReferenceCodeRepo(_session).GetByDomain(ReferenceCodeRepo.RELATED_NONRELATED, true);
            data.ListStatus = new ListStatusRepo(_session).GetAll().ToList();
            return data;
        }

        public EquityHeaderDTO InsertEquityHeader(EquityHeader data)
        {
            data.CreateDate = SessionManager.SystemDate;
            var comRepo = new CompanyRepo(_session);
            var eqRepo = new EquityHeaderRepo(_session);
            if (data.EquityCompanyID.HasValue)
            {
                var com = comRepo.GetByID(data.EquityCompanyID.Value);
                if (com != null)
                    data.EquityCompanyName = com.CompanyNameTh;
            }

            eqRepo.Save(data);
            _session.Flush();

            //TODO: จัดเก็บข้อมูลเป็น history จากหน้า Header ที่มีการบันทึกมา  ตอนไหนบ้าง ????
            InsertEquityPrice(data);

            var result = new EquityHeaderDTO
            {
                Header = data,
                Prices = new EquityPriceRepo(SessionManager.CurrentSession).GetListByHeaderID(data.EquityHeaderID),
                Transactions = new EquityTransactionRepo(SessionManager.CurrentSession).GetListByHeaderID(data.EquityHeaderID)
            };
            return result;
        }

        private void InsertEquityPrice(EquityHeader header)
        {
            var eqRepo = new EquityPriceRepo(_session);
            EquityPrice price = null;
            var sysdate = SessionManager.SystemDate;
            if (header.BidPriceDate.HasValue)
            {
                price = new EquityPrice
                {
                    EquityHeaderID = header.EquityHeaderID,
                    TypePrice = "BID PRICE",
                    Price = header.BidPricePerUnit,
                    PriceDate = sysdate
                };
                eqRepo.Save(price);
            }
            if (header.BVPriceDate.HasValue)
            {
                price = new EquityPrice
                {
                    EquityHeaderID = header.EquityHeaderID,
                    TypePrice = "BV PRICE",
                    Price = header.BVPricePerUnit,
                    PriceDate = sysdate
                };
                eqRepo.Save(price);
            }
            if (header.FVPriceDate.HasValue)
            {
                price = new EquityPrice
                {
                    EquityHeaderID = header.EquityHeaderID,
                    TypePrice = "FV PRICE",
                    Price = header.FVPricePerUnit,
                    PriceDate = sysdate
                };
                eqRepo.Save(price);
            }
            if (header.ClosePriceDate.HasValue)
            {
                price = new EquityPrice
                {
                    EquityHeaderID = header.EquityHeaderID,
                    TypePrice = "CLOSE PRICE",
                    Price = header.ClosePricePerUnit,
                    PriceDate = sysdate
                };
                eqRepo.Save(price);
            }
            _session.Flush();
        }

        public EquityHeaderDTO UpdateEquityHeader(EquityHeader data)
        {

            data.ModifyDate = SessionManager.SystemDate;
            var equityRepo = new EquityHeaderRepo(_session);
            var tempHeader = equityRepo.GetByID(data.EquityHeaderID);
            if (tempHeader == null)
                throw new Exception("Header was not found with ID : " + data.EquityHeaderID);
            //if (data.ModifyDate != tempHeader.ModifyDate)
            //    throw new Exception(string.Format("Update Timestamp failed. (Concurrency control Error {0} : {1})", tempHeader.ModifyDate, data.ModifyDate));

            if (data.EquityCompanyID.HasValue)
            {
                var comRepo = new CompanyRepo(_session);
                var com = comRepo.GetByID(data.EquityCompanyID.Value);
                if (com != null)
                    data.EquityCompanyName = com.CompanyNameTh;
            }
            _session.Evict(tempHeader);
            equityRepo.Update(data);
            _session.Flush();
            var result = new EquityHeaderDTO
            {
                Header = data,
                Transactions =
                    new EquityTransactionRepo(SessionManager.CurrentSession).GetListByHeaderID(data.EquityHeaderID)
            };
            return result;
        }

        public EquityTransaction InsertEquityTransaction(EquityTransaction data)
        {
            data.CreateDate = SessionManager.SystemDate;
            new EquityTransactionRepo(_session).Save(data);
            //_session.Flush();
            return data;
        }

        public EquityTransaction UpdateEquityTransaction(EquityTransaction data)
        {
            var repo = new EquityTransactionRepo(_session);
            var temp = repo.GetByID(data.EquityTransactionID);
            if (temp == null)
                throw new Exception(string.Format("Equity Transaction ID : {0} was not found.", data.EquityTransactionID));
            ////concurrency control
            //if (temp.ModifyDate  != data.ModifyDate)
            //    throw new Exception(string.Format("Update Timestamp failed. (Concurrency control Error {0} : {1})", temp.ModifyDate, data.ModifyDate));
            _session.Evict(temp);
            data.ModifyDate = SessionManager.SystemDate;
            repo.Update(data);
            //_session.Flush();
            return data;
        }

        public EquityTransactionScreenData GetEquityTransactionScreenData(int? headerId, int? transactionId, string transactionType)
        {
            var data = new EquityTransactionScreenData();
            if (transactionId.HasValue)
            {
                data.Transaction = new EquityTransactionRepo(SessionManager.CurrentSession).GetByID(transactionId.Value);
                if (headerId.HasValue && headerId.Value != data.Transaction.EquityHeaderID)
                    throw new Exception(string.Format("Equity {0} is not equals the parameter value : {1}", data.Transaction.EquityTransactionID, headerId.Value));
            }
            if (headerId.HasValue)
                data.Header = new EquityHeaderRepo(SessionManager.CurrentSession).GetByID(headerId.Value);
            else
            {
                if (transactionId.HasValue && data.Transaction != null)
                {
                    data.Header = new EquityHeaderRepo(SessionManager.CurrentSession).GetByID(data.Transaction.EquityHeaderID.Value);
                }
            }

            data.InvolvedType = new InvolvedPartyTypeRepo(_session).GetByName(data.Header.InvolvedPartyTypeName);

            if (transactionType == "Guarantee")
            {
                data.Obligations = new ObligationRepo(_session).GetAll().ToList();
                data.ObligationNOs = new ObligationNORepo(_session).GetAll().ToList();
            }
            else
            {
                data.PaymentTypes = new PaymentTypeRepo(_session).GetAll().ToList();
            }

            data.KeepAtList = new ReferenceCodeRepo(_session).GetByDomain(ReferenceCodeRepo.KEEP_AT, true);
            data.PhysicalList = new ReferenceCodeRepo(_session).GetByDomain(ReferenceCodeRepo.PHYSICAL, true);
            data.Brokers = new BrokerRepo(_session).GetAll().ToList();

            return data;
        }

        public EquityHeaderDTO GetEquityPrivilegeDataByHeaderId(int headerId)
        {
            var header = new EquityHeaderRepo(SessionManager.CurrentSession).GetByID(headerId);
            if (null == header)
            {
                throw new Exception(string.Format("Equity Header ID : {0} was not found.", headerId));
            }
            var privileges = new EquityPrivilegeRepo(SessionManager.CurrentSession).GetListByHeaderID(headerId);
            var involvedType = new InvolvedPartyTypeRepo(_session).GetByName(header.InvolvedPartyTypeName);

            return new EquityHeaderDTO() { Header = header, Privileges = privileges, InvolvedPartyType = involvedType };
        }

        public EquityPrivilegeScreenData GetEquityPrivilegeScreenData(int? headerId, int? privilegeId)
        {
            var data = new EquityPrivilegeScreenData();
            if (privilegeId != null)
            {
                data.Privilege = new EquityPrivilegeRepo(SessionManager.CurrentSession).GetByID(privilegeId.Value);
                if (headerId != null && headerId.Value != data.Privilege.EquityHeaderID)
                    throw new Exception(string.Format("Equity {0} is not equals the parameter value : {1}", data.Privilege.EquityHeaderID, headerId.Value));
            }
            if (headerId != null)
                data.Header = new EquityHeaderRepo(SessionManager.CurrentSession).GetByID(headerId.Value);
            else
            {
                if (privilegeId.HasValue && data.Privilege != null)
                {
                    data.Header = new EquityHeaderRepo(SessionManager.CurrentSession).GetByID(data.Privilege.EquityHeaderID.GetValueOrDefault());
                }
            }
            if (null == data.Header)
            {
                throw new Exception(string.Format("Equity Header ID : {0} was not found.", headerId));
            }
            if (privilegeId.HasValue)
            {
                data.Privilege = new EquityPrivilegeRepo(SessionManager.CurrentSession).GetByID(privilegeId.Value);
            }

            data.PaymentTypes = new PaymentTypeRepo(_session).GetAll().ToList();
            data.InvolvedType = new InvolvedPartyTypeRepo(_session).GetByName(data.Header.InvolvedPartyTypeName);

            return data;
        }

        public EquityPrivilege InsertEquityPrivilege(EquityPrivilege data)
        {
            data.CreateDate = SessionManager.SystemDate;
            var repo = new EquityPrivilegeRepo(_session);
            repo.Save(data);
            //_session.Flush();
            return data;
        }

        public EquityPrivilege UpdateEquityPrivilege(EquityPrivilege data)
        {
            var repo = new EquityPrivilegeRepo(_session);
            var temp = repo.GetByID(data.EquityPrivilegeID);
            if (temp == null)
                throw new Exception(string.Format("Privilege ID : {0} was not found.", data.EquityPrivilegeID));
            ////concurrency control
            //if (temp.ModifyDate  != data.ModifyDate)
            //    throw new Exception(string.Format("Update Timestamp failed. (Concurrency control Error {0} : {1})", temp.ModifyDate, data.ModifyDate));
            _session.Evict(temp);
            data.ModifyDate = SessionManager.SystemDate;
            repo.Update(data);
            //_session.Flush();
            return data;
        }


    }
}
